package org.rm.controladores;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rm.entidades.Experiencia;
import org.rm.entidades.Jugador;
import org.rm.entidades.Partida;
import org.rm.entidades.exp.ExperienciaParcial;
import org.rm.entidades.jpa.ExperienciaParcialController;
import org.rm.entidades.jpa.JpaExperiencia;
import org.rm.entidades.jpa.JugadoresJpaController;
import org.rm.entidades.jpa.PartidaJpaController;
import org.rm.entidades.jpa.exceptions.NonexistentEntityException;

/**
 * Clase para gestionar las experiencias
 * 
 * @author ffbeltran
 */
public class ControladorExperiencia {

	/**
	 * Método que añade una nueva experiencia. 
	 * @param exp experiencia a añadir
	 * @param jugadores que participan en la partida
	 * @return devuelve la experiencia base añadida
	 */
	public Experiencia nuevaExperiencia(Experiencia exp, Collection<Jugador> jugadores) {
		exp.setId(null);
		exp.actualizaExp();
		JpaExperiencia.create(exp);
		calculaExperiencia(exp, jugadores);
		return exp;
	}

	/**
	 * Método que modifica una experiencia
	 * @param exp experiencia que ha sido modificada
	 * @param jugadores que participan en la partida
	 */
	public void modificaExperiencia(Experiencia exp, Collection<Jugador> jugadores) {
		Experiencia antiguo;
		try {
			antiguo = JpaExperiencia.findExperiencia(exp.getClass(), exp.getId());
			if (antiguo.getExp() == null)
				antiguo.actualizaExp();
			antiguo.setExp(antiguo.getExp() * -1);
			exp.actualizaExp();
			JpaExperiencia.edit(exp);
			List<Experiencia> expList = new ArrayList<Experiencia>();
			expList.add(antiguo);
			expList.add(exp);
			calculaExperiencia(expList, jugadores);
		} catch (NonexistentEntityException ex) {
			ex.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * Elimina una experiencia determinada
	 * @param exp experiencia a eliminar
	 * @param jugadores que participan en la partida
	 */
	public void eliminaExperiencia(Experiencia exp, Collection<Jugador> jugadores) {
		if (exp != null) {
			exp.actualizaExp();
			exp.setExp(exp.getExp() * -1);
		}
		try {
			JpaExperiencia.destroy(exp.getClass(), exp.getId());
			calculaExperiencia(exp, jugadores);
		} catch (NonexistentEntityException ex) {
			ex.printStackTrace();
		}
	}
	
	public List<Experiencia> consultaExperiencias(Class<Experiencia> clazz, Integer idPartida) {
		return JpaExperiencia.findExperienciaEntities(clazz, idPartida);
	}

	private void calculaExperiencia(Experiencia experiencia,
			Collection<Jugador> jugadores) {
		List<Experiencia> expList = new ArrayList<Experiencia>();
		expList.add(experiencia);
		calculaExperiencia(expList, jugadores);
	}

	private void calculaExperiencia(List<? extends Experiencia> experiencia,
			Collection<Jugador> jugadores) {
		Map<Partida, Integer> expCompartida = new HashMap<Partida, Integer>();

		for (Partida aux : PartidaJpaController.findPartidaEntities()) {
			expCompartida.put(aux, 0);
		}

		for (Experiencia exp : experiencia) {
		    Jugador jugadorActual = exp.getJugador();
		    int expSign = (exp.getExp() >= 0) ? 1 : -1;
		    int expAbs = Math.abs(exp.getExp());
		    int expComp = (int) Math.ceil(((double) expAbs
		            * exp.getCompartido() / 100));
		    int expJugador = (expAbs - expComp) * expSign;
		    expComp = (int) Math.ceil((double) expComp / jugadores.size());
		    Partida p = exp.getPartida();
		    addExpJugador(jugadorActual, expJugador, p);
		    Integer aux = expCompartida.get(p);
		    expCompartida.put(p, aux + (expComp * expSign));
		}

		for (Partida p : expCompartida.keySet()) {
			int expCompartidaGeneral = expCompartida.get(p);
			for (Jugador jugadorActual : jugadores) {
				addExpJugador(jugadorActual, expCompartidaGeneral, p);
			}
		}
	}

	private void addExpJugador(Jugador jugador, int exp, Partida partida) {
		boolean exist = false;
		ExperienciaParcial exParcial;

		for (ExperienciaParcial aux : jugador.getExperiencia()) {
			if (aux.getPartida().equals(partida)) {
				exParcial = aux;
				exParcial.setExperiencia(exParcial.getExperiencia() + exp);
				exist = true;
				break;
			}
		}
		if (!exist) {
			exParcial = new ExperienciaParcial(exp, partida);
			ExperienciaParcialController.create(exParcial);
			jugador.getExperiencia().add(exParcial);
		}
		try {
			JugadoresJpaController.edit(jugador);
		} catch (NonexistentEntityException e) {
			e.printStackTrace();
		}
	}

}
